/*
 * Copyright 2007-2008 Michele Mostarda ( michele.mostarda@gmail.com ).
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.asemantics.anthill.chatconsole;

import org.apache.tools.ant.Project;
import org.asemantics.anthill.CommandListenerTask;
import org.jivesoftware.smack.XMPPException;

/**
 * This class represents a command line chat manager.
 *
 * @author Michele Mostarda
 */
public class ChatCommandLine {

    /**
     * The console version string.
     */
    public static final String CONSOLE_VERSION = "0.8";

    /**
     * The token separator for chat commandline.
     */
    public static final String COMMAND_TOKEN_SEPARATOR = " ";

    /**
     * The help command.
     */
    public static final String COMMAND_HELP = "help";

    /**
     * The long description of the command help.
     */
    public static final String COMMAND_HELP_LONG_DESC  = "returns help on a specific command: use as 'help <command>'";

    /**
     * No command arguments constant.
     */
    protected static final String[] NO_ARGS = new String[0];

    /**
     * The commands model.
     */
    private CommandsProvider commandsProvider;

    /**
     * Constructor.
     *
     * @param cp the commands provider to use for this chat command line.
     */
    public ChatCommandLine(CommandsProvider cp) {
        if(cp == null) {
            throw new NullPointerException("cp cannot be null");
        }

        commandsProvider = cp;
    }

    /**
     * Processes a chat entry.
     *
     * @param commandListenerTask the listener task.
     * @param chatConsole the chat console generating commands.
     * @param entry the chat entry i.e. the text sent with carriage return.
     */
    public void processChatEntry(CommandListenerTask commandListenerTask, ChatConsoleOutputStream chatConsole, String entry) throws XMPPException {
        if(entry == null) {
            return;
        }

        String[] parts = entry.split(COMMAND_TOKEN_SEPARATOR);
        if(parts.length == 0) {
            chatConsole.println("Invalid empty command: '" + entry + "'");
            return;
        }

        String command = parts[0].trim();
        String[] arguments;
        if(parts.length > 0) {
            arguments = new String[parts.length - 1];
            for(int i = 1; i < parts.length; i++) {
                arguments[i - 1] = parts[i].trim();
            }
        } else {
            arguments = NO_ARGS;
        }

        chatConsole.flushprint("processing message: '" + command + "'");
        boolean success = processCommand(commandListenerTask, chatConsole, command, arguments);
        chatConsole.println( success ? "Done ;)" : "Failure :(");

    }

    /**
     * Processes a chat command.
     * 
     * @param chatConsole
     * @param commandName
     * @param arguments
     * @return <code>true</code>if te command succeed, <code>false</code> otherwise.
     */
    private boolean processCommand(CommandListenerTask commandListenerTask, ChatConsoleOutputStream chatConsole, String commandName, String[] arguments) {

        // Check if command exists.
        if( ! commandsProvider.isCommandName(commandName)) {
            commandListenerTask.log("Not command name: '" + commandName + "'", Project.MSG_DEBUG);
            chatConsole.println("Unknown command: '" + commandName + "' :|");
            chatConsole.newline();
            printGenericHelp(chatConsole);
            return false;
        }

        // Check if command is help.
        if(COMMAND_HELP.equalsIgnoreCase(commandName)) {
            printSpecificHelp(chatConsole, arguments);
            return true;
        }

        // Process generic command.
        Command command;
        try {
            command = commandsProvider.getCommand(commandName);
            return command.execute(commandListenerTask, chatConsole, commandName, arguments);
        } catch (Throwable t) {
            commandListenerTask.log("Error during execution of command: '" + commandName + "': " + t.getMessage(), Project.MSG_ERR);
            chatConsole.println("An error occurred during the invocation of command '" + commandName + "'");
            chatConsole.println(t.getMessage());
            chatConsole.newline();
            return false;
        }
    }

    /**
     * Prints a generic help message.
     *
     * @param chatConsole
     */
    private void printGenericHelp(ChatConsoleOutputStream chatConsole) {
        chatConsole.println("chat console version " + CONSOLE_VERSION);
        chatConsole.println("print '" + COMMAND_HELP + "' to obtain help");
        chatConsole.println("print '" + COMMAND_HELP + " <command_name>' to obtain help on a specific command");
        chatConsole.newline();

        chatConsole.println("Available commands:");
        chatConsole.newline();
        for(String commandName : commandsProvider.getCommandNames()) {
            chatConsole.println( commandName + ": " + commandsProvider.getCommandShortDescription(commandName) );
        }
        chatConsole.newline();
    }

    /**
     * Prints a specific help message.
     * 
     * @param chatConsole
     * @param arguments
     */
    private void printSpecificHelp(ChatConsoleOutputStream chatConsole, String[] arguments) {
        if(arguments.length == 0) {
            printGenericHelp(chatConsole);
            return;
        }

        String helpTarget = arguments[0];
        // help help :)
        if(COMMAND_HELP.equals(helpTarget)) {
            chatConsole.println(COMMAND_HELP_LONG_DESC);
            chatConsole.newline();
            return;
        }

        // Check tha thte required command is know.
        if( ! commandsProvider.isCommandName(helpTarget)) {
            chatConsole.println("unknown command '" + helpTarget + "'");
            chatConsole.newline();
            return;
        }

        // Returs the description of the command.
        String longDescription = commandsProvider.getCommandLongDescription(helpTarget);
        chatConsole.println("command '" + helpTarget + "': \t\t\t" + longDescription);
        chatConsole.newline();
    }

}
